"""
提示词服务模块
提供提示词模板管理、参数渲染、使用记录等功能
"""
from typing import Dict, List, Optional, Any, Union
from datetime import datetime
import json
import re
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_, func

from models.prompt_template import (
    PromptTemplate, 
    PromptParameter, 
    PromptUsageRecord,
    PromptCategory,
    PromptTemplateVersion,
    ParameterType,
    OutputFormat
)
from core.database import get_db
from core.logging_config import get_logger
from core.exceptions import ValidationError, AIServiceError

logger = get_logger("prompt_service")


class PromptTemplateService:
    """提示词模板服务"""
    
    def __init__(self, db: Session):
        self.db = db
    
    def create_template(
        self,
        name: str,
        content: str,
        description: str = None,
        category: str = None,
        service_type: str = None,
        service_id: str = None,
        output_format: str = OutputFormat.JSON,
        tags: List[str] = None,
        parameters: List[Dict[str, Any]] = None,
        is_system: bool = False,
        enable_thinking: bool = False,
        created_by: int = None
    ) -> PromptTemplate:
        """创建提示词模板"""
        
        # 验证名称唯一性
        existing = self.db.query(PromptTemplate).filter(
            and_(
                PromptTemplate.name == name,
                PromptTemplate.is_deleted == False
            )
        ).first()
        if existing:
            raise ValidationError(f"提示词模板 '{name}' 已存在")
        
        # 创建模板
        template = PromptTemplate(
            name=name,
            content=content,
            description=description,
            category=category,
            service_type=service_type,
            service_id=service_id,
            output_format=output_format,
            tags=tags or [],
            is_system=is_system,
            enable_thinking=enable_thinking,
            version="1.0"
        )
        
        self.db.add(template)
        self.db.flush()  # 获取ID
        
        # 创建参数
        if parameters:
            for param_data in parameters:
                self._create_parameter(template.id, param_data)
        
        self.db.commit()
        self.db.refresh(template)
        
        logger.info(f"创建提示词模板: {name}")
        return template
    
    def update_template(
        self,
        template_id: int,
        **kwargs
    ) -> PromptTemplate:
        """更新提示词模板"""
        
        template = self.get_template_by_id(template_id)
        
        # 记录版本
        if 'content' in kwargs and kwargs['content'] != template.content:
            self._create_version(template.id, template.content)
        
        # 更新字段
        for key, value in kwargs.items():
            if hasattr(template, key):
                setattr(template, key, value)
        
        template.updated_at = datetime.now()
        self.db.commit()
        self.db.refresh(template)
        
        logger.info(f"更新提示词模板: {template.name}")
        return template
    
    def delete_template(self, template_id: int) -> bool:
        """删除提示词模板"""
        
        template = self.get_template_by_id(template_id)
        template.soft_delete()
        self.db.commit()
        
        logger.info(f"删除提示词模板: {template.name}")
        return True
    
    def get_template_by_id(self, template_id: int) -> PromptTemplate:
        """根据ID获取提示词模板"""
        
        template = self.db.query(PromptTemplate).filter(
            and_(
                PromptTemplate.id == template_id,
                PromptTemplate.is_deleted == False
            )
        ).first()
        
        if not template:
            raise ValidationError(f"提示词模板 ID {template_id} 不存在")
        
        return template
    
    def get_templates(
        self,
        category: str = None,
        service_type: str = None,
        search: str = None,
        is_active: bool = True,
        page: int = 1,
        page_size: int = 20
    ) -> Dict[str, Any]:
        """获取提示词模板列表"""
        
        query = self.db.query(PromptTemplate).filter(
            PromptTemplate.is_deleted == False
        )
        
        # 筛选条件
        if category:
            query = query.filter(PromptTemplate.category == category)
        if service_type:
            query = query.filter(PromptTemplate.service_type == service_type)
        if is_active is not None:
            query = query.filter(PromptTemplate.is_active == is_active)
        if search:
            query = query.filter(
                or_(
                    PromptTemplate.name.contains(search),
                    PromptTemplate.description.contains(search)
                )
            )
        
        # 总数
        total = query.count()
        
        # 分页
        offset = (page - 1) * page_size
        templates = query.order_by(PromptTemplate.created_at.desc()).offset(offset).limit(page_size).all()
        
        return {
            "items": [template.to_dict() for template in templates],
            "total": total,
            "page": page,
            "page_size": page_size,
            "pages": (total + page_size - 1) // page_size
        }
    
    def render_template(
        self,
        template_id: int,
        parameters: Dict[str, Any],
        user_id: int = None,
        enable_thinking: bool = None
    ) -> Dict[str, Any]:
        """渲染提示词模板"""
        
        template = self.get_template_by_id(template_id)
        
        # 验证参数
        validation_errors = template.validate_parameters(**parameters)
        if validation_errors:
            raise ValidationError(f"参数验证失败: {'; '.join(validation_errors)}")
        
        # 确定是否启用深度思考
        use_thinking = enable_thinking if enable_thinking is not None else template.enable_thinking
        
        # 渲染提示词
        start_time = datetime.now()
        rendered_content = template.render(**parameters)
        
        # 如果启用深度思考，添加思考提示词
        final_prompt = rendered_content
        
        render_time = (datetime.now() - start_time).total_seconds() * 1000
        
        result = {
            "template_id": template_id,
            "template_name": template.name,
            "rendered_prompt": final_prompt,
            "parameters": parameters,
            "output_format": template.output_format,
            "render_time": render_time,
            "enable_thinking": use_thinking,
        }
        
        # 记录使用
        self._record_usage(
            template_id=template_id,
            user_id=user_id,
            input_data=parameters,
            rendered_prompt=rendered_content,
            execution_time=int(render_time)
        )
        
        return result
    
    def add_parameter(
        self,
        template_id: int,
        param_data: Dict[str, Any]
    ) -> PromptParameter:
        """添加参数到模板"""
        
        template = self.get_template_by_id(template_id)
        
        # 检查参数名是否已存在
        existing = self.db.query(PromptParameter).filter(
            and_(
                PromptParameter.template_id == template_id,
                PromptParameter.name == param_data['name']
            )
        ).first()
        if existing:
            raise ValidationError(f"参数 '{param_data['name']}' 已存在")
        
        parameter = self._create_parameter(template_id, param_data)
        self.db.commit()
        
        logger.info(f"添加参数: {param_data['name']} 到模板: {template.name}")
        return parameter
    
    def update_parameter(
        self,
        parameter_id: int,
        **kwargs
    ) -> PromptParameter:
        """更新参数"""
        
        parameter = self.db.query(PromptParameter).filter(
            PromptParameter.id == parameter_id
        ).first()
        
        if not parameter:
            raise ValidationError(f"参数 ID {parameter_id} 不存在")
        
        # 更新字段
        for key, value in kwargs.items():
            if hasattr(parameter, key):
                setattr(parameter, key, value)
        
        self.db.commit()
        self.db.refresh(parameter)
        
        return parameter
    
    def delete_parameter(self, parameter_id: int) -> bool:
        """删除参数"""
        
        parameter = self.db.query(PromptParameter).filter(
            PromptParameter.id == parameter_id
        ).first()
        
        if not parameter:
            raise ValidationError(f"参数 ID {parameter_id} 不存在")
        
        self.db.delete(parameter)
        self.db.commit()
        
        return True
    
    def get_usage_statistics(
        self,
        template_id: int = None,
        start_date: datetime = None,
        end_date: datetime = None
    ) -> Dict[str, Any]:
        """获取使用统计"""
        
        query = self.db.query(PromptUsageRecord).filter(
            PromptUsageRecord.is_deleted == False
        )
        
        if template_id:
            query = query.filter(PromptUsageRecord.template_id == template_id)
        if start_date:
            query = query.filter(PromptUsageRecord.created_at >= start_date)
        if end_date:
            query = query.filter(PromptUsageRecord.created_at <= end_date)
        
        # 统计数据
        total_usage = query.count()
        success_count = query.filter(PromptUsageRecord.status == "success").count()
        error_count = query.filter(PromptUsageRecord.status == "error").count()
        
        # 平均执行时间
        avg_time = query.with_entities(
            func.avg(PromptUsageRecord.execution_time)
        ).scalar() or 0
        
        # 总token使用量
        total_tokens = query.with_entities(
            func.sum(PromptUsageRecord.token_count)
        ).scalar() or 0
        
        return {
            "total_usage": total_usage,
            "success_count": success_count,
            "error_count": error_count,
            "success_rate": (success_count / total_usage * 100) if total_usage > 0 else 0,
            "avg_execution_time": round(avg_time, 2),
            "total_tokens": total_tokens
        }
    
    def _create_parameter(
        self,
        template_id: int,
        param_data: Dict[str, Any]
    ) -> PromptParameter:
        """创建参数"""
        
        parameter = PromptParameter(
            template_id=template_id,
            name=param_data['name'],
            description=param_data.get('description', ''),
            param_type=param_data.get('param_type', ParameterType.STRING),
            field_path=param_data.get('field_path', ''),
            is_required=param_data.get('is_required', False),
            default_value=param_data.get('default_value', ''),
            enum_values=param_data.get('enum_values', []),
            min_length=param_data.get('min_length'),
            max_length=param_data.get('max_length'),
            min_value=param_data.get('min_value'),
            max_value=param_data.get('max_value'),
            pattern=param_data.get('pattern'),
            display_name=param_data.get('display_name', param_data['name']),
            placeholder=param_data.get('placeholder', ''),
            help_text=param_data.get('help_text', ''),
            ui_component=param_data.get('ui_component', 'input'),
            sort_order=param_data.get('sort_order', 0)
        )
        
        self.db.add(parameter)
        return parameter
    
    def _create_version(
        self,
        template_id: int,
        content: str,
        changelog: str = None
    ) -> PromptTemplateVersion:
        """创建版本记录"""
        
        template = self.get_template_by_id(template_id)
        
        # 获取下一个版本号
        last_version = self.db.query(PromptTemplateVersion).filter(
            PromptTemplateVersion.template_id == template_id
        ).order_by(PromptTemplateVersion.created_at.desc()).first()
        
        if last_version:
            version_parts = last_version.version.split('.')
            version_parts[-1] = str(int(version_parts[-1]) + 1)
            new_version = '.'.join(version_parts)
        else:
            new_version = "1.1"
        
        version = PromptTemplateVersion(
            template_id=template_id,
            version=new_version,
            content=content,
            changelog=changelog or "自动版本保存"
        )
        
        self.db.add(version)
        return version
    
    def _record_usage(
        self,
        template_id: int,
        user_id: int,
        input_data: Dict[str, Any],
        rendered_prompt: str,
        execution_time: int,
        output_data: Dict[str, Any] = None,
        status: str = "success",
        error_message: str = None
    ) -> PromptUsageRecord:
        """记录使用情况"""
        
        # 更新模板使用统计
        template = self.get_template_by_id(template_id)
        template.usage_count += 1
        template.last_used_at = datetime.now()
        
        # 创建使用记录
        record = PromptUsageRecord(
            template_id=template_id,
            user_id=user_id,
            input_data=input_data,
            rendered_prompt=rendered_prompt,
            output_data=output_data,
            execution_time=execution_time,
            status=status,
            error_message=error_message
        )
        
        self.db.add(record)
        return record
    
    def duplicate_template(
        self,
        template_id: int,
        new_name: str
    ) -> PromptTemplate:
        """复制模板"""
        
        template = self.get_template_by_id(template_id)
        
        # 创建新模板
        new_template = PromptTemplate(
            name=new_name,
            content=template.content,
            description=f"{template.description} (副本)",
            category=template.category,
            service_type=template.service_type,
            service_id=template.service_id,
            output_format=template.output_format,
            tags=template.tags,
            version="1.0"
        )
        
        self.db.add(new_template)
        self.db.flush()
        
        # 复制参数
        for param in template.parameters:
            new_param = PromptParameter(
                template_id=new_template.id,
                name=param.name,
                description=param.description,
                param_type=param.param_type,
                field_path=param.field_path,
                is_required=param.is_required,
                default_value=param.default_value,
                enum_values=param.enum_values,
                min_length=param.min_length,
                max_length=param.max_length,
                min_value=param.min_value,
                max_value=param.max_value,
                pattern=param.pattern,
                display_name=param.display_name,
                placeholder=param.placeholder,
                help_text=param.help_text,
                ui_component=param.ui_component,
                sort_order=param.sort_order
            )
            self.db.add(new_param)
        
        self.db.commit()
        self.db.refresh(new_template)
        
        logger.info(f"复制模板: {template.name} -> {new_name}")
        return new_template
    
    def validate_template_content(self, content: str, parameters: List[Dict[str, Any]]) -> List[str]:
        """验证模板内容"""
        
        errors = []
        
        # 检查参数占位符
        param_names = {param['name'] for param in parameters}
        placeholders = set(re.findall(r'\{(\w+)\}', content))
        
        # 检查未使用的参数
        unused_params = param_names - placeholders
        if unused_params:
            errors.append(f"未使用的参数: {', '.join(unused_params)}")
        
        # 检查未定义的占位符
        undefined_placeholders = placeholders - param_names
        if undefined_placeholders:
            errors.append(f"未定义的占位符: {', '.join(undefined_placeholders)}")
        
        return errors